package com.jming.jike.util;

import com.jming.jike.common.BusinessException;
import com.jming.jike.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author jinming.zhang
 * @version 0.0.1
 * @date 2022/04/26
 */
@Component
public class MinioUtils {

    @Resource
    private MinioClient minioClient;

    @Resource
    private MinioConfig minioConfig;

    /**
     * 查看bucket是否存在
     *
     * @param bucketName
     * @return boolean true 存在 false 不存在
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public boolean bucketExists(String bucketName) {

        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 创建bucket信息
     *
     * @param bucketName
     * @return boolean true 创建成功
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public boolean makeBucket(String bucketName) {

        try {
            if (bucketExists(bucketName)) {
                return true;
            }
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            return true;
        } catch (Exception e) {
            throw new BusinessException("创建bucket失败!");
        }
    }

    /**
     * 删除bucket
     *
     * @param bucketName
     * @return boolean
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public boolean removeBucket(String bucketName) {

        try {
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取所有bucket
     *
     * @param
     * @return List<Bucket>
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public List<Bucket> getAllBucketList() {

        try {
            return minioClient.listBuckets();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 文件上传
     *
     * @param bucketName
     * @param folderName 文件夹名称(末尾不要加"/") 除非有下级目录 否则不要加"/"
     * @param file
     * @return String 上传成功返回文件全路径名(不带Url)
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public String upload(String bucketName, String folderName, MultipartFile file) {

        try {
            String fileName = file.getOriginalFilename();
            if (fileName == null || fileName.isEmpty()) {
                return null;
            }
            String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            // 重新生成文件名称(默认创建一个以当前时间命名的文件夹 文件名称：当前时间+随机Id+文件后缀) 以免重名被覆盖
            String objectName = folderName + "/" + date + "/" + date + "-" + UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));

            // 上传文件 上传成功返回文件全路径名(不带Url)
            return minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType()).build()).object();
        } catch (Exception e) {
            throw new  RuntimeException("上传失败!");
        }
    }

    /**
     * 上传文件并得到永久访问路径
     * 如果文件没被删除, 则可永久访问
     * bucket必须设置为 public
     *
     * @param
     * @return String 访问的Url
     * @Author jinming.zhang
     * @Date 2022/4/27
     */
    public String uploadAndGetUrl(String bucketName, String folderName, MultipartFile file) {

        return minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/" + upload(bucketName, folderName, file);
    }

    /**
     * 查看文件
     *
     * @param objectName 上传成功后的文件名
     * @param bucketName bucket名称
     * @return String 文件Url
     * @Author jinming.zhang
     * @Date 2022/4/26
     */
    public String preview(String objectName, String bucketName) {

        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .object(objectName)
                    .bucket(bucketName)
                    .method(Method.GET).build());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 下载文件
     *
     * @param objectName
     * @param bucketName
     * @param res
     * @Author jinming.zhang
     * @Date 2022/4/27
     */
    public void download(String objectName, String bucketName, HttpServletResponse res) {

        try (GetObjectResponse response = minioClient.getObject(GetObjectArgs.builder()
                .object(objectName).bucket(bucketName).build())) {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = response.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                res.setContentType("application/force-download");
                res.addHeader("Content-Disposition",
                        "attachment;fileName=" + objectName.substring(objectName.lastIndexOf("/") + 1));
                try (ServletOutputStream stream = res.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("下载失败!");
        }
    }

    /**
     * 查看bucket里面所有的文件
     *
     * @param bucketName
     * @return List<Item>
     * @Author jinming.zhang
     * @Date 2022/4/27
     */
    public List<Item> objectList(String bucketName) {

        try {
            Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName).build());
            List<Item> items = new ArrayList<>();
            for (Result<Item> result : results) {
                items.add(result.get());
            }
            return items;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 删除文件
     *
     * @param objectName
     * @param bucketName
     * @return boolean
     * @Author jinming.zhang
     * @Date 2022/4/27
     */
    public boolean remove(String objectName, String bucketName) {

        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .object(objectName)
                    .bucket(bucketName)
                    .build());

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 批量删除文件
     *
     * @param objectNameList
     * @param bucketName
     * @return List<Result < DeleteError>>
     * @Author jinming.zhang
     * @Date 2022/4/27
     */
    public List<Result<DeleteError>> batchRemove(List<String> objectNameList, String bucketName) {

        List<DeleteObject> deleteObjectList = objectNameList.stream().map(DeleteObject::new).collect(Collectors.toList());
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder()
                .objects(deleteObjectList)
                .bucket(bucketName)
                .build());

        List<Result<DeleteError>> resultList = new ArrayList<>();
        for (Result<DeleteError> result : results) {
            resultList.add(result);
        }

        return resultList;
    }

    /**
     * 测试查看图片
     *
     * @param null
     * @Author jinming.zhang
     * @Date 2022/4/27
     * @return null
     */
//    public static void main(String[] args) {
//        try {
//            MinioClient build = MinioClient.builder()
//                    .endpoint("http://oss.jming956.cn")
//                    .credentials("userjming", "userJming")
//                    .build();
//            System.out.println(build.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
//                    .object("imge/桌面.jpg")
//                    .bucket("jike-take-out")
//                    .method(Method.GET).build()));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//    }

}
